package Init

import (
	"database/sql"
	"errors"
	"log"
	"runtime/debug"

	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/plugin/dbresolver"
)

func InitMysqlPool(path string) error {
	err := InitMysqlConf(path)
	if err != nil {
		return err
	}

	DBMapPool = map[string]*sql.DB{}
	GormMapPool = map[string]*gorm.DB{}
	for confName, DbConf := range MysqlMapCfg.List {
		db, err := gorm.Open(mysql.Open(DbConf.DataSourceName), &gorm.Config{
			QueryFields: true,
			Logger:      NewGormLogger(), // mysql 日志方案一
		})
		if err != nil {
			log.Fatalf("%+v\n%s", err, string(debug.Stack()))
			// return err
		}

		// mysql 日志方案二，不要和日志方案一同时打开
		// db.Use(&TracePlugin{})

		// 读写分离
		if len(DbConf.DataSourceRead) > 0 && DbConf.DataSourceRead != "" {
			err = db.Use(dbresolver.Register(
				dbresolver.Config{
					Replicas: []gorm.Dialector{mysql.Open(DbConf.DataSourceRead)},
					Policy:   dbresolver.RandomPolicy{},
				},
			))
			if err != nil {
				log.Fatalf("InitMysqlPool Use %+v\n %s", err, string(debug.Stack()))
				return err
			}
		}

		sqlDB, err := db.DB()
		if err != nil {
			log.Fatalf("%+v\n%s", err, string(debug.Stack()))
			// return err
		}

		sqlDB.SetMaxOpenConns(DbConf.MaxOpenConn)
		sqlDB.SetConnMaxLifetime(time.Duration(DbConf.MaxConnLifeTime) * time.Second)
		sqlDB.SetMaxIdleConns(DbConf.MaxIdleConn)

		DBMapPool[confName] = sqlDB
		GormMapPool[confName] = db
	}

	//手动配置连接
	if dbpool, err := GetDBPool("default_db"); err == nil {
		DBDefaultPool = dbpool
	}
	if dbpool, err := GetGormPool("default_db"); err == nil {
		GormDefaultPool = dbpool
	}
	return nil
}

func GetDBPool(name string) (*sql.DB, error) {
	if dbpool, ok := DBMapPool[name]; ok {
		return dbpool, nil
	}
	return nil, errors.New("get pool error")
}

func GetGormPool(name string) (*gorm.DB, error) {
	if dbpool, ok := GormMapPool[name]; ok {
		return dbpool, nil
	}
	return nil, errors.New("get pool error")
}

func CloseDB() error {
	for _, dbpool := range DBMapPool {
		err := dbpool.Close()
		if err != nil {
			log.Printf("close db pool fail, %+v", err)
			return err
		}
	}
	return nil
}
